﻿using System;

using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Windows.Forms;
using PasswordSafe.Classes;

namespace PasswordSafe.Xml
{
    public class PasswordReader : IDisposable
    {
        public PasswordReader(string xml)
            : base()
        {
            LoadXml(xml);
        }

        private PasswordReader()
            : base()
        {
        
        }

        public static IEnumerable<PasswordCategory> ReadCategories(string xml)
        {
            using (PasswordReader passwordReader = new PasswordReader(xml))
            {
                return passwordReader.Categories;
            }
        }

        private Dictionary<string, PasswordCategory> categories = new Dictionary<string, PasswordCategory>();


        public IEnumerable<PasswordCategory> Categories { get { return categories.Values; } }

        public IEnumerable<PasswordData> Passwords { get { return passwords; } }

        private void LoadXml(string xml)
        {
            passwords.Clear();

            StringReader sr = new StringReader(xml);
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreComments = true;
            settings.IgnoreWhitespace = true;
            using (XmlReader reader = XmlTextReader.Create(sr, settings))
            {
                if (reader.ReadToFollowing("categories"))
                {
                    ReadCategories(reader);
                }
                if (reader.ReadToFollowing("passwords"))
                {
                    ReadPasswords(reader);
                }
            }
        }

        private PasswordCategory FindCategory(string name)
        {
            if (string.IsNullOrEmpty(name)) return null;
            if (categories.ContainsKey(name)) return categories[name];
            return null;
        }

        private void ReadCategories(XmlReader reader)
        {
            categories.Clear();
            using (XmlReader subTree = reader.ReadSubtree())
            {
                subTree.ReadStartElement();
                while (subTree.Name == "category")
                {
                    PasswordCategory category = new PasswordCategory();
                    string name = subTree["name"];
                    category.Name = name.ToLower();
                    string title = subTree["title"];
                    category.Title = string.IsNullOrEmpty(title) ? name : title;
                    ReadCategoryFields(category, subTree);
                    if (!categories.ContainsKey(category.Name)) categories.Add(category.Name, category);
                    if (!subTree.ReadToNextSibling("category")) break;
                }
            }
        }

        private void ReadCategoryFields(PasswordCategory category, XmlReader reader)
        {
            using (XmlReader subTree = reader.ReadSubtree())
            {
                subTree.ReadStartElement();
                while (subTree.Name == "field" || subTree.Name == "separator")
                {
                    if (subTree.Name == "field")
                    {
                        FieldInfo field = new FieldInfo();
                        string name = subTree["name"];
                        string title = subTree["title"];
                        if (string.IsNullOrEmpty(title)) title = name;
                        field.Name = name.ToLower();
                        field.Title = title;
                        field.Type = GetType(subTree["type"]);
                        category.Fields.Add(field);
                    }
                    else
                    {
                        Separator separator = new Separator();
                        separator.Title = subTree["title"];
                        category.Fields.Add(separator);
                    }
                    subTree.Read();

                }
            }
        }

        private FieldType GetType(string name)
        {
            if (string.IsNullOrEmpty(name)) return FieldType.String;

            try
            {
                return (FieldType)Enum.Parse(typeof(FieldType), name, true);
            }
            catch
            {
                return FieldType.String;
            }
        }

        private void ReadPasswords(XmlReader reader)
        {
            using (XmlReader subTree = reader.ReadSubtree())
            {
                subTree.ReadStartElement();
                while (subTree.Name == "password")
                {
                    PasswordData data = new PasswordData();
                    data.Category = FindCategory(subTree["category"]);
                    passwords.Add(data);

                    if (subTree.MoveToFirstAttribute())
                    {
                        do
                        {
                            string name = subTree.Name;
                            string value = subTree.Value;

                            data.Values.Add(name, value);
                        } while (subTree.MoveToNextAttribute());
                    }
                    if (!subTree.ReadToNextSibling("password")) break;
                }
            }
        }

        private List<PasswordData> passwords = new List<PasswordData>();

        #region obsolete
#if false
        public IEnumerable<PasswordData> GetPasswords()
        {
            string path = @"\My Documents\" + fileName;
            StreamReader sr = File.OpenText(path);
            //using (FileStream stream = new FileStream(path, FileMode.Open))
            {
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.IgnoreComments = true;
                settings.IgnoreWhitespace = true;
                using (XmlReader reader = XmlTextReader.Create(sr, settings))
                {
                    if (reader.ReadToFollowing("passwords"))
                    {
                        using (XmlReader subTree = reader.ReadSubtree())
                        {
                            subTree.ReadStartElement();
                            while (subTree.Name == "item")
                            {
                                PasswordData data = new PasswordData();
                                data.Name = subTree["name"];
                                data.EMail = subTree["email"];
                                data.Password = subTree["password"];
                                data.Url = subTree["url"];
                                data.User = subTree["user"];
                                yield return data;
                                if (!subTree.ReadToNextSibling("item")) break;
                            }
                        }
                    }
                }
            }
        }
#endif
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
        }

        #endregion
    }
}
